import { match } from "ts-pattern";

import { BooleanInput } from "../../BooleanInput/BooleanInputSimple";
import { CSSUnitInput } from "../../CSSUnitInput/CSSUnitInput";
import { NamedListInput } from "../../ListInput/NamedListInput";
import { NumberInput } from "../../NumberInput/NumberInput";
import { DropdownSelect } from "../../OptionsDropdown/DropdownSelect";
import { RadioInputs } from "../../RadioInputs/RadioInputsSimple";
import type { InputOptions, KnownInputFieldTypes } from "../inputFieldTypes";

import { StringInput } from "./StringInput";

type SettingsInputElementProps = InputOptions & {
  id: string;
  label: string;
  /**
   * Due to dynamics of types the on change callback is a very general purpose
   * function that can take any of our input types as arguments. Type narrowing is
   * not really beneficial here since we already know the type and the callback is
   * generated by the code not provided by the user.
   */
  onChange: (newValue: KnownInputFieldTypes) => void;
};

export function SettingsInputElement(args: SettingsInputElementProps) {
  return match(args)
    .with({ inputType: "string" }, (x) => <StringInput {...x} />)
    .with({ inputType: "number" }, (x) => <NumberInput {...x} />)
    .with({ inputType: "cssMeasure" }, (x) => <CSSUnitInput {...x} />)
    .with({ inputType: "boolean" }, (x) => <BooleanInput {...x} />)
    .with({ inputType: "list" }, (x) => <NamedListInput {...x} />)
    .with({ inputType: "dropdown" }, (x) => <DropdownSelect {...x} />)
    .with({ inputType: "radio" }, (x) => <RadioInputs {...x} />)
    .otherwise(({ inputType }) => (
      <div>
        I don't know how to render the input of type {inputType} yet! Sorry.
      </div>
    ));
}
